package pub.cleangao.codegen.literal;

import lombok.extern.slf4j.Slf4j;
import pub.cleangao.codegen.GenConfigHolder;
import pub.cleangao.codegen.enquiry.TableInfo;
import pub.cleangao.codegen.sqlexe.DbType;
import pub.cleangao.codegen.sqlexe.Dialect;
import pub.cleangao.codegen.util.ClassField;
import pub.cleangao.codegen.util.EnjoyEngine;
import pub.cleangao.common.util.IOUtil;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;

import com.jfinal.template.Engine;


@Slf4j
public class LiteralProducer {

    private static final Engine engine = Engine.create("java-assembler");


    /**
     * 生成输出内容
     *
     * @param templatePath 模板路径
     * @param tableInfo    解析的表信息
     * @param config       配置信息
     */
    public static void generateCodeFile(TemplateType type, String templatePath, TableInfo tableInfo, GenConfigHolder config) {
        try {
            LiteralResult result = new LiteralResult();
            Map<String, Object> context = new HashMap<>();
            context.put("tableInfo", tableInfo);
            result.setFileName(ClassField.upperFirstLetter(tableInfo.javaTableName()));
            String moduleName = "";
            if (!config.isSinglePot()) {
                if (type.equals(TemplateType.API) ||
                        type.equals(TemplateType.API_DTO)) {
                    moduleName = config.getStubModule();
                    if (moduleName == null || moduleName.isBlank()) {
                        moduleName = ProjectStruct.serviceStubModule;
                    }
                } else {
                    moduleName = config.getServiceModule();
                    if (moduleName == null || moduleName.isBlank()) {
                        moduleName = ProjectStruct.serviceProviderModule;
                    }
                }

            }
            if (!moduleName.isBlank()) {
                moduleName = "/" + moduleName.trim();
            }
            String javaFolderPath = moduleName + "/" + ProjectStruct.javaCodePath;
            switch (type) {
                case DAO -> {
                    result.setClassName(result.getFileName() + ProjectStruct.daoSuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.daoPackage);
                }
                case SERVICE -> {
                    result.setClassName(result.getFileName() + ProjectStruct.serviceSuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.servicePackage);
                }
                case ENTITY -> {
                    result.setClassName(result.getFileName() + ProjectStruct.entitySuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.entityPackage);
                }
                case CONTROLLER -> {
                    result.setClassName(result.getFileName() + ProjectStruct.controllerSuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.controllerPackage);
                }
                case API -> {
                    result.setClassName(result.getFileName() + ProjectStruct.stubApiSuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.stubApiPackage);
                }
                case API_DTO -> {
                    result.setClassName(result.getFileName() + ProjectStruct.stubDtoSuffix);
                    result.setPackageName(config.getBasePackage() + "." + ProjectStruct.stubDtoPackage);
                }
            }
            context.put("package", result.getPackageName());
            context.put("daoPackage", config.getBasePackage() + "." + ProjectStruct.daoPackage);
            context.put("entityPackage", config.getBasePackage() + "." + ProjectStruct.entityPackage);
            context.put("dtoPackage", config.getBasePackage() + "." + ProjectStruct.stubDtoPackage);
            context.put("daoName", result.getFileName() + ProjectStruct.daoSuffix);
            context.put("entityName", result.getFileName() + ProjectStruct.entitySuffix);
            context.put("dtoName", result.getFileName() + ProjectStruct.stubDtoSuffix);
            context.put("className", result.getClassName());
            context.put("comment", tableInfo.getComment());
            context.put("author", config.getAuthor());
            context.put("datetime", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")));
            context.put("entityFieldOpening", ProjectStruct.entityFieldOpening);
            context.put("dbDialect", Dialect.fromDbType(DbType.of(config.getDbType())));
            result.setFolderPath(config.getRootPath() + javaFolderPath + result.getPackageName().replace(".", "/"));
            result.setFileName(result.getClassName() + ".java");
            result.setFilePath(result.getFolderPath() + "/" + result.getFileName());
            result.setContent(EnjoyEngine.assemble(templatePath, context));
            outputToDisk(result);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public static void outputToDisk(LiteralResult literal) {
        if (literal == null) {
            return;
        }
        File targetFolder = new File(literal.getFolderPath());
        if (!targetFolder.exists()) {
            boolean ok = targetFolder.mkdirs();
        }
        File target = new File(literal.getFilePath());
        InputStream inputStream = IOUtil.toInputStream(literal.getContent(), StandardCharsets.UTF_8);
        try {
            IOUtil.copy(inputStream, new FileOutputStream(target));
            log.info("file build: {}", literal.getFilePath());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}
